R Fundamentals 1 - Objective of workshop
To get acquainted with R and RStudio, and do calculations using
R.
What will this workshop cover?
The goal of this session is to get to started using RStudio, learn
how to use variables and solve basic calculations in R. We will
cover:
- Introduction to RStudio
- Using r as a calculator
- Assigning variables
- Numerical variables
Using R as a calculator
We can use R to do simple or advanced calculations for us. Remember
to run the code press the green play button or press Ctrl + Enter (or
Cmd + Enter on Mac).
## [1] 42
## [1] 1.25
## [1] 21
Exercise (R as calculator)
Use R to work out the following arithmetic:
44 * 26
9.6/1.6
(12+4)^2
(4*9)/(5+6)
(22/36) * 100
- The remainder of
55 / 2 (hint: look up r’s modulus
operator)
Assigning variables
A variable is a named storage of information. In our case today we
are storing numbers.
We can assign variables by using <-. You should see
the variable appear to your right in the global environment once you’ve
run this command (under Values).
We can then print the output of the variable by typing in its
name.
## [1] 155
When calling a variable, be careful to type it exactly (you can also
copy it or use code completion to help). The code below will give you an
error because we have spelt height incorrectly.
## Error in eval(expr, envir, enclos): object 'hieght' not found
We can do calculations on variables. We first assign the variables,
then use them in the calculation.
In the example below, Score1 is 42, Score2 is 92 and so on. If we
calculate Score1 * Score2 what is really happening is
42 * 92, as this is the data scored in those variables. Run
the code, and review the output as well as the variables we have made in
the global environment (top right panel in RStudio).
# test scores
Score1 <- 42
Score2 <- 92
Score3 <- 68
# average score calculation
AveScore <- (Score1+Score2+Score3)/3
# print average score
AveScore
## [1] 67.33333
You will have noticed the hashtags (#) with text in the
above example. These are called comments. In later R sessions we will
use a lot of comments to tell us (and others) what each line or section
of code is doing.
Assigning variables exercise 1
- Make a variable called my_height, and assign your height in cm (this
can be an estimate if you are not sure)
- Print the output of my_height
- Convert your height in cm to feet. Make a new variable called
my_height_feet, and assign the calculation of your height in cm to feet.
hint: there are 0.0328084 feet in 1 cm
- Print your my_height_feet variable
Reassigning variables
You can also change the value of a variable you have already
assigned. Here we are going to add our new pay check to our previous
bank balance.
Run this code to test it out:
# create variables
BankBalance <- 100
PayCheck <- 250
# add old bank balance and pay check, assigning result to bank balance
BankBalance <- BankBalance + PayCheck
# print bank balance
BankBalance
## [1] 350
Note that if you run
BankBalance <- BankBalance + PayCheck line of code twice
you will get a higher bank balance (600 rather than 350). This is
because code works sequentially in R and the order you run commands
matters. See the example below on what happens if we repeat adding
numbers to a total.
# variables
number <- 5
total <- 0
# adding number to total
total <- total + number
total
## [1] 5
total <- total + number
total
## [1] 10
total <- total + number
total
## [1] 15
Reassigning variables exercise
Try and add another pay check of £50 to the bank balance
variable.
- Make a variable called PayCheck2 with a value of 50
- Assign BankBalance, and calculate BankBalance + PayCheck2
- Print the outcome
- You go out for dinner with friends and spend 36.55. Make a variable
called dinner with the value of 36.55
- Assign BankBalance, and calculate BankBalance - dinner
- Print the outcome hint: if this doesn’t work run the code chunk
with the bank balance variable
Assigning variables exercise 2
Use R to work out a body mass index (BMI) of someone who is 79kg, and
1.77m tall.
- Assign the variables of weight and height
- Assign the variable of BMI, and calculate the BMI based of the
weight and height variables
- Print the outcome
- Add comments on what each line of code is doing
# your code here
# Exercise: BMI calculation
# assign variables of weight and height
# BMI calculation
# print outcome
Overall grade calculation debugging exercise
Debug the code below that is finding the weighted average of a
students coursework and exam scores. You should find three errors:
- logic (maths) error
- syntax error
- naming error
# Exercise: weighted average debugging
exam1 <- 52
coursework1 <- 82
exam2 <- 78
coursework2 < 48
## Error in eval(expr, envir, enclos): object 'coursework2' not found
cw_weight <- 0.4
ex_weight <- 0.6
course1 <- (exam1 * ex_weight) + (coursework * cw_weight)
## Error in eval(expr, envir, enclos): object 'coursework' not found
course2 <- (exam2 * ex_weight) + (coursework2 * cw_weight)
## Error in eval(expr, envir, enclos): object 'coursework2' not found
overall_grade <- (course1 + course2)/3
## Error in eval(expr, envir, enclos): object 'course1' not found
## Error in eval(expr, envir, enclos): object 'overall_grade' not found
Salary calculation exercise
Robin and Charlie are a married couple, one gets paid an hourly rate,
the other has an annual salary. They want to workout how much annual
salary they have combined before tax. Out of interest Charlie also wants
to know what her hourly rate is before tax.
They used simple calculations using the following formulas:
(number hours worked per week x hourly rate) x number of weeks worked
= annual salary (annual salary ÷ number of weeks in a year) ÷ hours
worked per week = hourly rate
Re-arrange the code so the calculations run. You should have both the
combined salary and Charlies hourly rate calculations printed.
# weeks in year
weeksYear <- 52
# Charlies hourly rate
Charlie_HourlyRate <- (Charlie_annualSary / weeksYear)/Charlie_hoursPerWeek
## Error in eval(expr, envir, enclos): object 'Charlie_annualSary' not found
## Error in eval(expr, envir, enclos): object 'Charlie_HourlyRate' not found
# salaries
Robin_HourlyRate <- 16.5
Charlie_annualSary <- 31800
# Combined salaries
CombinedSalaries <- Robin_annualSalary + Charlie_annualSary
## Error in eval(expr, envir, enclos): object 'Robin_annualSalary' not found
## Error in eval(expr, envir, enclos): object 'CombinedSalaries' not found
# Robins annual salary
Robin_annualSalary <- (Robin_hoursPerWeek * Robin_HourlyRate) * Robin_weeksWorking
## Error in eval(expr, envir, enclos): object 'Robin_hoursPerWeek' not found
# hours worked
Robin_hoursPerWeek <- 25
Robin_weeksWorking <- 48
Charlie_hoursPerWeek <- 35
Individual coding challenge
A take home coding task for you.
Task: Splitting a Pizza Pilgrims restaurant bill between 3 friends;
Roger, Amal and Genevieve.
- Roger has a Calzone Ripieno (£11), and a San Pellegrino (£2).
- Amal has a Bufala (£9), and Birra Moretti (£4.50).
- Genevieve has a Portobello Mushroom & Truffle (£10), and water
to drink.
- Genevieve and Amal also share a Nutella Pizza ring for dessert
(£5.5).

- Make a variable for each friend that is the sum of their order
(e.g. Roger would be 11 + 2)
- Make a variable for the shared food
- Make a variable called TotalBill, and calculate their total
bill
- For those that shared food, add the shared food to their bill
- Comment your code
- Print the total bill and what each friend owes
# individual coding challenge
R Fundamentals 2 - Objective of workshop
To work with vectors, a key data type in R, and learn to use built in
functions on those vectors.
What will this workshop cover?
In this workshop, the aim is to cover some basics of using variables
and vectors in R. We will be covering:
- Vectors
- Introduction to functions
- Use indexing to extract information from a vector
Vectors
A vector is a set of information contained together in a specific
order.
To make a vector you combine variables using the c()
function (more on functions later); also known as concatenation. To call
the c() function we use brackets () with the numbers we
want separated by a comma.
The first way of making a vector is to add the arguments you want,
numbers in this case.
Run this code chunk to test it out.
vect1 <- c(1,6,19,4,9)
vect1
## [1] 1 6 19 4 9
We can also combine predefined variables and vectors together to
create a new vector.
x <- 30
vect2 <- c(vect1, 22, 7, x)
vect2
## [1] 1 6 19 4 9 22 7 30
Another way of making a vector is using the colon (:),
which can be done without the c function. We can tell R to select a
sequence of integers from x to y, or 5 through to 10 in our example.
## [1] 5 6 7 8 9 10
We can also do some basic calculations on vectors. These occur
elementwise (one element at a time).
## [1] 1.0 1.2 1.4 1.6 1.8 2.0
As you can see this divides all elements in the vector by 5.
Vector exercise 1
- Make a vector called x with integers from 8 through to 14
- Add 5 to your x vector (be sure to save as result back to x)
- Make a vector called y with variables 34, 55, 13, 71, 98, 43 and
25
- Take 12 from your y vector (be sure to save as result back to
y)
- Times x vector by y
Functions: what are they and how to use them
A function is code organised together to perform a specific task. The
function will take in an input, perform a task, then return an output.
They are the backbone of R, which comes built in with a wide array of
functions.
The function(input) format is the fundamental way to
call and use a function in R. function is the name of
the function we are using, input is the argument or
data we are passing to the function.
For example:
# running times (mins)
runTimes <- c(31, 50, 15, 19, 23, 34, 9)
# mean running time
aveRun <- mean(runTimes)
aveRun
## [1] 25.85714
# tidy up result
aveRun <- round(aveRun, digits = 2)
aveRun
## [1] 25.86
Here we are using the functions c() to concatenate,
mean() calculates the mean, and round() rounds
to specific decimal places. Notice with the round()
function we have digits = 2, which tells the function to
round to two decimal places; this is called a argument.
Functions exercise
We are on a walking exercise plan, where we increase our step count
by a thousand each day, starting at 1000 steps and ending on 12000.
- Make a variable called steps using the
seq() function
that increases steps from 1000 to 12000 by increments of 500
- Workout the sum of how many steps we have done in total from this
exercise plan
- Workout out the median amount of steps we have done on this exercise
plan
- Comment your code
# your code here
# steps
# total steps
# median steps
Indexing vectors
Indexing is a technical term for accessing elements of a vector.
Think of it like selecting books from a book shelf. The vector is your
book shelf, the index determines the book, or books you pick from the
shelf.
To index in R you use the square brackets [] after you
type the name of the vector to index from. You then put the numerical
position of the elements you want to index in the square brackets. For
example, if I wanted to select the first element from my vector I would
do something like data[1]; data is my data, and 1 is the
element I want to index.
Run the example code chunks to see the results:
someNumbers <- c(4, 26, 11, 15, 18, 9, 3, 1)
# indexing the 6th element
someNumbers[6]
## [1] 9
Indexing elements 1 to 4
## [1] 4 26 11 15
Dropping elements 5 to 7
## [1] 4 26 11 15 1
Indexing 1, 5, and 8
## [1] 4 18 1
Indexing exercise 1
You’ve been keeping track of how much coffee you drink each day for a
two week period. We want to split this into week 1 and 2. Using the code
below follow the following steps:
- Find out the mean for weekOne and WeekTwo vectors.
mean doesn’t work for weekTwo and gives back
NA. Print your weekTwo vector to look at the data.
- Check the length of your weekTwo vector by running the
length() function on the weekTwo vector.
- There are a few ways ways to fix this, try and find at least two
different ways.
hint: the mean() function has an argument called na.rm, type and
run ?mean() to look at the help page
# vector with n coffee per day for two weeks
coffee <- c(3, 5, 4, 2, 3, 1, 1, 6, 2, 3, 2, 4, 2, 1)
# weeks
weekOne <- coffee[1:7]
weekTwo <- coffee[8:15]
# your code here
Using indexing to change values
Using indexing you can change the value of an item, or multiple
items, in a vector. This is very useful if you spot a data error and
want to fix it in the code. We will using similar principles in later
sessions.
This is a combination of what we have learned so far, with
reassigning data to variables/vectors and indexing. For example,
data[1] <- 5 means we take the first element (or data
point) from data, and assign the number 5 as a replacement.
Run the code below to see the example:
someNumbers <- c(4, 26, 11, 15, 18, 9, 3, 1)
someNumbers
## [1] 4 26 11 15 18 9 3 1
# Change one item
someNumbers[8] <- 50
someNumbers
## [1] 4 26 11 15 18 9 3 50
# Change multiple
someNumbers[1:3] <- c(19, 20, 21)
someNumbers
## [1] 19 20 21 15 18 9 3 50
In the first change, we changed the 8th element of the someNumbers
data to 50 (it was 1 previously). In the second change, we changed the
first, second and third elements to 19, 20, and 21 (changing from 4, 26,
11).
Indexing exercise 2
You decided to track your total monthly expenditures for the year to
find out more about your monthly spending. You’re interested in your
spending per quarter, biggest spending month, and lowest spending
month.
- Make a variable called myExpenses with the following data: 976, 631,
1231, 1120, 1374, 873, 1244, 1398, 989, 1034, 579 and 1506. Each item
represents each month, first is January spending, second is February
spending etc.
- You realise the spending for some of the months is wrong. January
should be 921, August should be 1419, and November should be 703. Use
indexing to change the values in myExpenses so they are correct.
- Using indexing make a vector for the first quarter of the year. Call
it Q1 and make sure the first three months are indexed.
- Repeat for quarters 2, 3, and 4.
- Workout the average spending for each quarter. Which had the biggest
spending?
- Using the
which.max() and which.min()
functions on your myExpenses vector, find out which months had the
highest and lowest spending. Assign the result of each to a variable
(minSpend, maxSpend).
- Now you know the highest and lowest spending months, put them into a
vector together called MaxMin by indexing from the myExpenses
vector.
Individual coding challenge 1
You decide to calculate your commuting times over a weekly period.
You decide to see if you can workout, based off your weekly commute, how
much commuting you will do on average this month.
- Replicate the commute variable four times using
rep()
and assign to a variable called commute_est.
- Calculate the mean of commute_est and assign to a variable called
aveCommute.
- Round the value of aveCommute to two decimal places using
round() and assign to aveCommute.
- You miss timed your Tuesday commute, it should be 37 instead of 33.
To make replacement easier use
sort() on commute_est, and
assign to a variable called commute_sort.
- Replace the 33 values with 37 using indexing in the variable
commute_sort.
- Re-calculate and round aveCommute as per instructions two and
three.
- Test out the following functions on the commute_sort variable:
unique() and
sort(commute, decreasing = TRUE).
commute <- c(41, 33, 44, 52, 36, 39)
# enter your code here
Individual coding challenge 2
For this individual coding challenge we will be looking at Lional
Messi’s season appearances and goals from 2004-2020.
The code below has been jumbled up and will not run. Your challenge
is to re-order it so it runs correctly. It should print out summary
statistics for season goal ratio and age band goal ratios, as well as
which year was his most and least prolific, and how many years that took
him.
# print career ratio
careerGoalRatio
## Error in eval(expr, envir, enclos): object 'careerGoalRatio' not found
# which season had the worst goal ratio
season[which.max(goalRatio)]
## Error in eval(expr, envir, enclos): object 'season' not found
# combine age band ratios to a vector
ageGoalRatio <- c(round(mean(teenageGoalRatio), digits = 2),
round(mean(twentiesGoalRatio), digits = 2),
round(mean(thirtiesGoalRatio), digits = 2))
## Error in mean(teenageGoalRatio): object 'teenageGoalRatio' not found
# add in appearance, goal and season data
appearances <- c(9,25,36,40,51,53,55,60,50,46,57,49,52,54,50,44)
goals <- c(1,8,17,16,38,47,53,73,60,41,58,41,54,45,51,31)
season <- c(2004,2005,2006,2007,2008,2009,2010,2011,2012,
2013,2014,2015,2016,2017,2018,2019)
# which season had the best goal ratio
season[which.min(goalRatio)]
## Error in which.min(goalRatio): object 'goalRatio' not found
# goal ratio per age band (teenager, 20's, 30's)
teenageGoalRatio <- goalRatio[1:3]
## Error in eval(expr, envir, enclos): object 'goalRatio' not found
twentiesGoalRatio <- goalRatio[4:13]
## Error in eval(expr, envir, enclos): object 'goalRatio' not found
thirtiesGoalRatio <- goalRatio[14:16]
## Error in eval(expr, envir, enclos): object 'goalRatio' not found
# summary results
summary(goalRatio)
## Error in summary(goalRatio): object 'goalRatio' not found
## Error in summary(ageGoalRatio): object 'ageGoalRatio' not found
# how many years playing to reach best goal ratio
season[which.min(goalRatio)] - season[1]
## Error in which.min(goalRatio): object 'goalRatio' not found
# work out appearance to goal ratio per season and total career ratio
goalRatio <- round(appearances/goals, digits = 2)
careerGoalRatio <- round(sum(appearances)/sum(goals), digits = 2)
LS0tCnRpdGxlOiAiUiBGdW5kYW1lbnRhbHMgMSAmIDI6IEZhc3QtdHJhY2siCmF1dGhvcjoKICAgLSBuYW1lOiBBbmRyZXcgTW9sZXMKICAgICBhZmZpbGlhdGlvbjogTGVhcm5pbmcgRGV2ZWxvcGVyLCBEaWdpdGFsIFNraWxscyBMYWIKZGF0ZTogImByIGZvcm1hdChTeXMudGltZSgpLCAnJWQgJUIsICVZJylgIgpvdXRwdXQ6IAogIGh0bWxfZG9jdW1lbnQ6IAogICAgdGhlbWU6IHJlYWRhYmxlCiAgICBoaWdobGlnaHQ6IHB5Z21lbnRzCiAgICBrZWVwX21kOiBubwogICAgY29kZV9kb3dubG9hZDogdHJ1ZQogICAgdG9jOiB0cnVlCiAgICB0b2NfZmxvYXQ6IAogICAgICBjb2xsYXBzZWQ6IHRydWUKLS0tCgojIFIgRnVuZGFtZW50YWxzIDEgLSBPYmplY3RpdmUgb2Ygd29ya3Nob3AKClRvIGdldCBhY3F1YWludGVkIHdpdGggUiBhbmQgUlN0dWRpbywgYW5kIGRvIGNhbGN1bGF0aW9ucyB1c2luZyBSLgoKIyBXaGF0IHdpbGwgdGhpcyB3b3Jrc2hvcCBjb3Zlcj8KClRoZSBnb2FsIG9mIHRoaXMgc2Vzc2lvbiBpcyB0byBnZXQgdG8gc3RhcnRlZCB1c2luZyBSU3R1ZGlvLCBsZWFybiBob3cgdG8gdXNlIHZhcmlhYmxlcyBhbmQgc29sdmUgYmFzaWMgY2FsY3VsYXRpb25zIGluIFIuIFdlIHdpbGwgY292ZXI6CgotICAgSW50cm9kdWN0aW9uIHRvIFJTdHVkaW8KLSAgIFVzaW5nIHIgYXMgYSBjYWxjdWxhdG9yCi0gICBBc3NpZ25pbmcgdmFyaWFibGVzCi0gICBOdW1lcmljYWwgdmFyaWFibGVzCgotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KCiMgVXNpbmcgUiBhcyBhIGNhbGN1bGF0b3IKCldlIGNhbiB1c2UgUiB0byBkbyBzaW1wbGUgb3IgYWR2YW5jZWQgY2FsY3VsYXRpb25zIGZvciB1cy4gUmVtZW1iZXIgdG8gcnVuIHRoZSBjb2RlIHByZXNzIHRoZSBncmVlbiBwbGF5IGJ1dHRvbiBvciBwcmVzcyBDdHJsICsgRW50ZXIgKG9yIENtZCArIEVudGVyIG9uIE1hYykuCgpgYGB7cn0KNyAqIDYKNSAvICgyXjIpCigxNiAtIDQpICsgKDEgKiA5KQpgYGAKCiMjIEV4ZXJjaXNlIChSIGFzIGNhbGN1bGF0b3IpCgpVc2UgUiB0byB3b3JrIG91dCB0aGUgZm9sbG93aW5nIGFyaXRobWV0aWM6CgoxKSAgYDQ0ICogMjZgCjIpICBgOS42LzEuNmAKMykgIGAoMTIrNCleMmAKNCkgIGAoNCo5KS8oNSs2KWAKNSkgIGAoMjIvMzYpICogMTAwYAo2KSAgVGhlIHJlbWFpbmRlciBvZiBgNTUgLyAyYCAoaGludDogbG9vayB1cCByJ3MgbW9kdWx1cyBvcGVyYXRvcikKCmBgYHtyfQojIHR5cGUgeW91ciBjb2RlIGhlcmUKCmBgYAoKIyBBc3NpZ25pbmcgdmFyaWFibGVzCgpBIHZhcmlhYmxlIGlzIGEgbmFtZWQgc3RvcmFnZSBvZiBpbmZvcm1hdGlvbi4gSW4gb3VyIGNhc2UgdG9kYXkgd2UgYXJlIHN0b3JpbmcgbnVtYmVycy4KCldlIGNhbiBhc3NpZ24gdmFyaWFibGVzIGJ5IHVzaW5nIGA8LWAuIFlvdSBzaG91bGQgc2VlIHRoZSB2YXJpYWJsZSBhcHBlYXIgdG8geW91ciByaWdodCBpbiB0aGUgZ2xvYmFsIGVudmlyb25tZW50IG9uY2UgeW91J3ZlIHJ1biB0aGlzIGNvbW1hbmQgKHVuZGVyIFZhbHVlcykuCgpgYGB7cn0KaGVpZ2h0IDwtIDE1NQpgYGAKCldlIGNhbiB0aGVuIHByaW50IHRoZSBvdXRwdXQgb2YgdGhlIHZhcmlhYmxlIGJ5IHR5cGluZyBpbiBpdHMgbmFtZS4KCmBgYHtyfQpoZWlnaHQKYGBgCgpXaGVuIGNhbGxpbmcgYSB2YXJpYWJsZSwgYmUgY2FyZWZ1bCB0byB0eXBlIGl0IGV4YWN0bHkgKHlvdSBjYW4gYWxzbyBjb3B5IGl0IG9yIHVzZSBjb2RlIGNvbXBsZXRpb24gdG8gaGVscCkuIFRoZSBjb2RlIGJlbG93IHdpbGwgZ2l2ZSB5b3UgYW4gZXJyb3IgYmVjYXVzZSB3ZSBoYXZlIHNwZWx0IGhlaWdodCBpbmNvcnJlY3RseS4KCmBgYHtyIGVycm9yPVRSVUV9CmhpZWdodApgYGAKCldlIGNhbiBkbyBjYWxjdWxhdGlvbnMgb24gdmFyaWFibGVzLiBXZSBmaXJzdCBhc3NpZ24gdGhlIHZhcmlhYmxlcywgdGhlbiB1c2UgdGhlbSBpbiB0aGUgY2FsY3VsYXRpb24uCgpJbiB0aGUgZXhhbXBsZSBiZWxvdywgU2NvcmUxIGlzIDQyLCBTY29yZTIgaXMgOTIgYW5kIHNvIG9uLiBJZiB3ZSBjYWxjdWxhdGUgYFNjb3JlMSAqIFNjb3JlMmAgd2hhdCBpcyByZWFsbHkgaGFwcGVuaW5nIGlzIGA0MiAqIDkyYCwgYXMgdGhpcyBpcyB0aGUgZGF0YSBzY29yZWQgaW4gdGhvc2UgdmFyaWFibGVzLiBSdW4gdGhlIGNvZGUsIGFuZCByZXZpZXcgdGhlIG91dHB1dCBhcyB3ZWxsIGFzIHRoZSB2YXJpYWJsZXMgd2UgaGF2ZSBtYWRlIGluIHRoZSBnbG9iYWwgZW52aXJvbm1lbnQgKHRvcCByaWdodCBwYW5lbCBpbiBSU3R1ZGlvKS4KCmBgYHtyfQojIHRlc3Qgc2NvcmVzClNjb3JlMSA8LSA0MgpTY29yZTIgPC0gOTIKU2NvcmUzIDwtIDY4CiMgYXZlcmFnZSBzY29yZSBjYWxjdWxhdGlvbgpBdmVTY29yZSA8LSAoU2NvcmUxK1Njb3JlMitTY29yZTMpLzMKIyBwcmludCBhdmVyYWdlIHNjb3JlCkF2ZVNjb3JlCmBgYAoKWW91IHdpbGwgaGF2ZSBub3RpY2VkIHRoZSBoYXNodGFncyAoYCNgKSB3aXRoIHRleHQgaW4gdGhlIGFib3ZlIGV4YW1wbGUuIFRoZXNlIGFyZSBjYWxsZWQgY29tbWVudHMuIEluIGxhdGVyIFIgc2Vzc2lvbnMgd2Ugd2lsbCB1c2UgYSBsb3Qgb2YgY29tbWVudHMgdG8gdGVsbCB1cyAoYW5kIG90aGVycykgd2hhdCBlYWNoIGxpbmUgb3Igc2VjdGlvbiBvZiBjb2RlIGlzIGRvaW5nLgoKYGBge3J9CiMgdGhpcyBpcyBhIGNvbW1lbnQKYGBgCgojIyBBc3NpZ25pbmcgdmFyaWFibGVzIGV4ZXJjaXNlIDEKCjEpICBNYWtlIGEgdmFyaWFibGUgY2FsbGVkIG15X2hlaWdodCwgYW5kIGFzc2lnbiB5b3VyIGhlaWdodCBpbiBjbSAodGhpcyBjYW4gYmUgYW4gZXN0aW1hdGUgaWYgeW91IGFyZSBub3Qgc3VyZSkKMikgIFByaW50IHRoZSBvdXRwdXQgb2YgbXlfaGVpZ2h0CjMpICBDb252ZXJ0IHlvdXIgaGVpZ2h0IGluIGNtIHRvIGZlZXQuIE1ha2UgYSBuZXcgdmFyaWFibGUgY2FsbGVkIG15X2hlaWdodF9mZWV0LCBhbmQgYXNzaWduIHRoZSBjYWxjdWxhdGlvbiBvZiB5b3VyIGhlaWdodCBpbiBjbSB0byBmZWV0LiAqaGludDogdGhlcmUgYXJlIDAuMDMyODA4NCBmZWV0IGluIDEgY20qCjQpICBQcmludCB5b3VyIG15X2hlaWdodF9mZWV0IHZhcmlhYmxlCgpgYGB7cn0KIyB5b3VyIGNvZGUgaGVyZQoKYGBgCgojIFJlYXNzaWduaW5nIHZhcmlhYmxlcwoKWW91IGNhbiBhbHNvIGNoYW5nZSB0aGUgdmFsdWUgb2YgYSB2YXJpYWJsZSB5b3UgaGF2ZSBhbHJlYWR5IGFzc2lnbmVkLiBIZXJlIHdlIGFyZSBnb2luZyB0byBhZGQgb3VyIG5ldyBwYXkgY2hlY2sgdG8gb3VyIHByZXZpb3VzIGJhbmsgYmFsYW5jZS4KCipSdW4gdGhpcyBjb2RlIHRvIHRlc3QgaXQgb3V0OioKCmBgYHtyfQojIGNyZWF0ZSB2YXJpYWJsZXMKQmFua0JhbGFuY2UgPC0gMTAwClBheUNoZWNrIDwtIDI1MAojIGFkZCBvbGQgYmFuayBiYWxhbmNlIGFuZCBwYXkgY2hlY2ssIGFzc2lnbmluZyByZXN1bHQgdG8gYmFuayBiYWxhbmNlCkJhbmtCYWxhbmNlIDwtIEJhbmtCYWxhbmNlICsgUGF5Q2hlY2sKIyBwcmludCBiYW5rIGJhbGFuY2UKQmFua0JhbGFuY2UKYGBgCgpOb3RlIHRoYXQgaWYgeW91IHJ1biBgQmFua0JhbGFuY2UgPC0gQmFua0JhbGFuY2UgKyBQYXlDaGVja2AgbGluZSBvZiBjb2RlIHR3aWNlIHlvdSB3aWxsIGdldCBhIGhpZ2hlciBiYW5rIGJhbGFuY2UgKDYwMCByYXRoZXIgdGhhbiAzNTApLiBUaGlzIGlzIGJlY2F1c2UgY29kZSB3b3JrcyBzZXF1ZW50aWFsbHkgaW4gUiBhbmQgdGhlIG9yZGVyIHlvdSBydW4gY29tbWFuZHMgbWF0dGVycy4gU2VlIHRoZSBleGFtcGxlIGJlbG93IG9uIHdoYXQgaGFwcGVucyBpZiB3ZSByZXBlYXQgYWRkaW5nIG51bWJlcnMgdG8gYSB0b3RhbC4KCmBgYHtyfQojIHZhcmlhYmxlcwpudW1iZXIgPC0gNQp0b3RhbCA8LSAwCiMgYWRkaW5nIG51bWJlciB0byB0b3RhbAp0b3RhbCA8LSB0b3RhbCArIG51bWJlcgp0b3RhbAp0b3RhbCA8LSB0b3RhbCArIG51bWJlcgp0b3RhbAp0b3RhbCA8LSB0b3RhbCArIG51bWJlcgp0b3RhbApgYGAKCiMjIFJlYXNzaWduaW5nIHZhcmlhYmxlcyBleGVyY2lzZQoKVHJ5IGFuZCBhZGQgYW5vdGhlciBwYXkgY2hlY2sgb2YgwqM1MCB0byB0aGUgYmFuayBiYWxhbmNlIHZhcmlhYmxlLgoKMSkgIE1ha2UgYSB2YXJpYWJsZSBjYWxsZWQgUGF5Q2hlY2syIHdpdGggYSB2YWx1ZSBvZiA1MAoyKSAgQXNzaWduIEJhbmtCYWxhbmNlLCBhbmQgY2FsY3VsYXRlIEJhbmtCYWxhbmNlICsgUGF5Q2hlY2syCjMpICBQcmludCB0aGUgb3V0Y29tZQo0KSAgWW91IGdvIG91dCBmb3IgZGlubmVyIHdpdGggZnJpZW5kcyBhbmQgc3BlbmQgMzYuNTUuIE1ha2UgYSB2YXJpYWJsZSBjYWxsZWQgZGlubmVyIHdpdGggdGhlIHZhbHVlIG9mIDM2LjU1CjUpICBBc3NpZ24gQmFua0JhbGFuY2UsIGFuZCBjYWxjdWxhdGUgQmFua0JhbGFuY2UgLSBkaW5uZXIKNikgIFByaW50IHRoZSBvdXRjb21lICpoaW50OiBpZiB0aGlzIGRvZXNuJ3Qgd29yayBydW4gdGhlIGNvZGUgY2h1bmsgd2l0aCB0aGUgYmFuayBiYWxhbmNlIHZhcmlhYmxlKgoKYGBge3J9CiMgeW91ciBjb2RlIGhlcmUKCmBgYAoKIyMgQXNzaWduaW5nIHZhcmlhYmxlcyBleGVyY2lzZSAyCgpVc2UgUiB0byB3b3JrIG91dCBhIGJvZHkgbWFzcyBpbmRleCAoQk1JKSBvZiBzb21lb25lIHdobyBpcyA3OWtnLCBhbmQgMS43N20gdGFsbC4KCjEpICBBc3NpZ24gdGhlIHZhcmlhYmxlcyBvZiB3ZWlnaHQgYW5kIGhlaWdodAoyKSAgQXNzaWduIHRoZSB2YXJpYWJsZSBvZiBCTUksIGFuZCBjYWxjdWxhdGUgdGhlIEJNSSBiYXNlZCBvZiB0aGUgd2VpZ2h0IGFuZCBoZWlnaHQgdmFyaWFibGVzCjMpICBQcmludCB0aGUgb3V0Y29tZQo0KSAgQWRkIGNvbW1lbnRzIG9uIHdoYXQgZWFjaCBsaW5lIG9mIGNvZGUgaXMgZG9pbmcKCmBgYHtyfQojIHlvdXIgY29kZSBoZXJlCiMgRXhlcmNpc2U6IEJNSSBjYWxjdWxhdGlvbgojIGFzc2lnbiB2YXJpYWJsZXMgb2Ygd2VpZ2h0IGFuZCBoZWlnaHQKCgojIEJNSSBjYWxjdWxhdGlvbgoKCiMgcHJpbnQgb3V0Y29tZQoKYGBgCgojIyBPdmVyYWxsIGdyYWRlIGNhbGN1bGF0aW9uIGRlYnVnZ2luZyBleGVyY2lzZQoKRGVidWcgdGhlIGNvZGUgYmVsb3cgdGhhdCBpcyBmaW5kaW5nIHRoZSB3ZWlnaHRlZCBhdmVyYWdlIG9mIGEgc3R1ZGVudHMgY291cnNld29yayBhbmQgZXhhbSBzY29yZXMuIFlvdSBzaG91bGQgZmluZCB0aHJlZSBlcnJvcnM6CgotICAgbG9naWMgKG1hdGhzKSBlcnJvcgotICAgc3ludGF4IGVycm9yCi0gICBuYW1pbmcgZXJyb3IKCmBgYHtyIGVycm9yPVRSVUV9CiMgRXhlcmNpc2U6IHdlaWdodGVkIGF2ZXJhZ2UgZGVidWdnaW5nCmV4YW0xIDwtIDUyCmNvdXJzZXdvcmsxIDwtIDgyCmV4YW0yIDwtIDc4CmNvdXJzZXdvcmsyIDwgNDgKCmN3X3dlaWdodCA8LSAwLjQKZXhfd2VpZ2h0IDwtIDAuNgoKY291cnNlMSA8LSAoZXhhbTEgKiBleF93ZWlnaHQpICsgKGNvdXJzZXdvcmsgKiBjd193ZWlnaHQpCmNvdXJzZTIgPC0gKGV4YW0yICogZXhfd2VpZ2h0KSArIChjb3Vyc2V3b3JrMiAqIGN3X3dlaWdodCkKCm92ZXJhbGxfZ3JhZGUgPC0gKGNvdXJzZTEgKyBjb3Vyc2UyKS8zCgpvdmVyYWxsX2dyYWRlCmBgYAoKIyMgU2FsYXJ5IGNhbGN1bGF0aW9uIGV4ZXJjaXNlCgpSb2JpbiBhbmQgQ2hhcmxpZSBhcmUgYSBtYXJyaWVkIGNvdXBsZSwgb25lIGdldHMgcGFpZCBhbiBob3VybHkgcmF0ZSwgdGhlIG90aGVyIGhhcyBhbiBhbm51YWwgc2FsYXJ5LiBUaGV5IHdhbnQgdG8gd29ya291dCBob3cgbXVjaCBhbm51YWwgc2FsYXJ5IHRoZXkgaGF2ZSBjb21iaW5lZCBiZWZvcmUgdGF4LiBPdXQgb2YgaW50ZXJlc3QgQ2hhcmxpZSBhbHNvIHdhbnRzIHRvIGtub3cgd2hhdCBoZXIgaG91cmx5IHJhdGUgaXMgYmVmb3JlIHRheC4KClRoZXkgdXNlZCBzaW1wbGUgY2FsY3VsYXRpb25zIHVzaW5nIHRoZSBmb2xsb3dpbmcgZm9ybXVsYXM6CgoobnVtYmVyIGhvdXJzIHdvcmtlZCBwZXIgd2VlayB4IGhvdXJseSByYXRlKSB4IG51bWJlciBvZiB3ZWVrcyB3b3JrZWQgPSBhbm51YWwgc2FsYXJ5IChhbm51YWwgc2FsYXJ5IMO3IG51bWJlciBvZiB3ZWVrcyBpbiBhIHllYXIpIMO3IGhvdXJzIHdvcmtlZCBwZXIgd2VlayA9IGhvdXJseSByYXRlCgpSZS1hcnJhbmdlIHRoZSBjb2RlIHNvIHRoZSBjYWxjdWxhdGlvbnMgcnVuLiBZb3Ugc2hvdWxkIGhhdmUgYm90aCB0aGUgY29tYmluZWQgc2FsYXJ5IGFuZCBDaGFybGllcyBob3VybHkgcmF0ZSBjYWxjdWxhdGlvbnMgcHJpbnRlZC4KCmBgYHtyIGVycm9yPVRSVUV9CiMgd2Vla3MgaW4geWVhcgp3ZWVrc1llYXIgPC0gNTIKCiMgQ2hhcmxpZXMgaG91cmx5IHJhdGUKQ2hhcmxpZV9Ib3VybHlSYXRlIDwtIChDaGFybGllX2FubnVhbFNhcnkgLyB3ZWVrc1llYXIpL0NoYXJsaWVfaG91cnNQZXJXZWVrCkNoYXJsaWVfSG91cmx5UmF0ZQoKIyBzYWxhcmllcwpSb2Jpbl9Ib3VybHlSYXRlIDwtIDE2LjUKQ2hhcmxpZV9hbm51YWxTYXJ5IDwtIDMxODAwCgojIENvbWJpbmVkIHNhbGFyaWVzCkNvbWJpbmVkU2FsYXJpZXMgPC0gUm9iaW5fYW5udWFsU2FsYXJ5ICsgQ2hhcmxpZV9hbm51YWxTYXJ5CkNvbWJpbmVkU2FsYXJpZXMKCiMgUm9iaW5zIGFubnVhbCBzYWxhcnkKUm9iaW5fYW5udWFsU2FsYXJ5IDwtIChSb2Jpbl9ob3Vyc1BlcldlZWsgKiBSb2Jpbl9Ib3VybHlSYXRlKSAqIFJvYmluX3dlZWtzV29ya2luZwoKIyBob3VycyB3b3JrZWQKUm9iaW5faG91cnNQZXJXZWVrIDwtIDI1ClJvYmluX3dlZWtzV29ya2luZyA8LSA0OApDaGFybGllX2hvdXJzUGVyV2VlayA8LSAzNQpgYGAKCiMgSW5kaXZpZHVhbCBjb2RpbmcgY2hhbGxlbmdlCgpBIHRha2UgaG9tZSBjb2RpbmcgdGFzayBmb3IgeW91LgoKVGFzazogU3BsaXR0aW5nIGEgUGl6emEgUGlsZ3JpbXMgcmVzdGF1cmFudCBiaWxsIGJldHdlZW4gMyBmcmllbmRzOyBSb2dlciwgQW1hbCBhbmQgR2VuZXZpZXZlLgoKLSAgIFJvZ2VyIGhhcyBhIENhbHpvbmUgUmlwaWVubyAowqMxMSksIGFuZCBhIFNhbiBQZWxsZWdyaW5vICjCozIpLgotICAgQW1hbCBoYXMgYSBCdWZhbGEgKMKjOSksIGFuZCBCaXJyYSBNb3JldHRpICjCozQuNTApLgotICAgR2VuZXZpZXZlIGhhcyBhIFBvcnRvYmVsbG8gTXVzaHJvb20gJiBUcnVmZmxlICjCozEwKSwgYW5kIHdhdGVyIHRvIGRyaW5rLgotICAgR2VuZXZpZXZlIGFuZCBBbWFsIGFsc28gc2hhcmUgYSBOdXRlbGxhIFBpenphIHJpbmcgZm9yIGRlc3NlcnQgKMKjNS41KS4KCiFbXShodHRwczovL2dpdGh1Yi5jb20vYW5kcmV3bW9sZXMyL3JUcmFpbkludHJvZHVjdGlvbi9ibG9iL21haW4vci1mdW5kYW1lbnRhbHMtMS9JbWFnZXMvcGl6emFQLmpwZz9yYXc9dHJ1ZSkKCjEpICBNYWtlIGEgdmFyaWFibGUgZm9yIGVhY2ggZnJpZW5kIHRoYXQgaXMgdGhlIHN1bSBvZiB0aGVpciBvcmRlciAoZS5nLiBSb2dlciB3b3VsZCBiZSAxMSArIDIpCjIpICBNYWtlIGEgdmFyaWFibGUgZm9yIHRoZSBzaGFyZWQgZm9vZAozKSAgTWFrZSBhIHZhcmlhYmxlIGNhbGxlZCBUb3RhbEJpbGwsIGFuZCBjYWxjdWxhdGUgdGhlaXIgdG90YWwgYmlsbAo0KSAgRm9yIHRob3NlIHRoYXQgc2hhcmVkIGZvb2QsIGFkZCB0aGUgc2hhcmVkIGZvb2QgdG8gdGhlaXIgYmlsbAo1KSAgQ29tbWVudCB5b3VyIGNvZGUKNikgIFByaW50IHRoZSB0b3RhbCBiaWxsIGFuZCB3aGF0IGVhY2ggZnJpZW5kIG93ZXMKCmBgYHtyfQojIGluZGl2aWR1YWwgY29kaW5nIGNoYWxsZW5nZQpgYGAKCiMgUmVjb21tZW5kZWQgbGlua3MKClJlY29tbWVuZGVkIGZvciBtb3JlIGluZm9ybWF0aW9uIG9uIHRoZSBSU3R1ZGlvIGVudmlyb25tZW50OiA8aHR0cHM6Ly9ybGFkaWVzc3lkbmV5Lm9yZy9jb3Vyc2VzL3J5b3V3aXRobWUvMDEtYmFzaWNiYXNpY3MtMS8+CgpSZWNvbW1lbmRlZCBmb3IgbW9yZSBpbmZvcm1hdGlvbiBvbiB1c2luZyBSIE1hcmtkb3duOiA8aHR0cHM6Ly9ybWFya2Rvd24ucnN0dWRpby5jb20vbGVzc29uLTEuaHRtbD4KCi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQoKIyBSIEZ1bmRhbWVudGFscyAyIC0gT2JqZWN0aXZlIG9mIHdvcmtzaG9wCgpUbyB3b3JrIHdpdGggdmVjdG9ycywgYSBrZXkgZGF0YSB0eXBlIGluIFIsIGFuZCBsZWFybiB0byB1c2UgYnVpbHQgaW4gZnVuY3Rpb25zIG9uIHRob3NlIHZlY3RvcnMuIAoKIyBXaGF0IHdpbGwgdGhpcyB3b3Jrc2hvcCBjb3Zlcj8KCkluIHRoaXMgd29ya3Nob3AsIHRoZSBhaW0gaXMgdG8gY292ZXIgc29tZSBiYXNpY3Mgb2YgdXNpbmcgdmFyaWFibGVzIGFuZCB2ZWN0b3JzIGluIFIuIFdlIHdpbGwgYmUgY292ZXJpbmc6CgotICAgVmVjdG9ycwotICAgSW50cm9kdWN0aW9uIHRvIGZ1bmN0aW9ucwotICAgVXNlIGluZGV4aW5nIHRvIGV4dHJhY3QgaW5mb3JtYXRpb24gZnJvbSBhIHZlY3RvciAKCi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQoKIyBWZWN0b3JzCgpBIHZlY3RvciBpcyBhIHNldCBvZiBpbmZvcm1hdGlvbiBjb250YWluZWQgdG9nZXRoZXIgaW4gYSBzcGVjaWZpYyBvcmRlci4KClRvIG1ha2UgYSB2ZWN0b3IgeW91IGNvbWJpbmUgdmFyaWFibGVzIHVzaW5nIHRoZSBgYygpYCBmdW5jdGlvbiAobW9yZSBvbiBmdW5jdGlvbnMgbGF0ZXIpOyBhbHNvIGtub3duIGFzIGNvbmNhdGVuYXRpb24uIFRvIGNhbGwgdGhlIGBjKClgIGZ1bmN0aW9uIHdlIHVzZSBicmFja2V0cyAoKSB3aXRoIHRoZSBudW1iZXJzIHdlIHdhbnQgc2VwYXJhdGVkIGJ5IGEgY29tbWEuCgpUaGUgZmlyc3Qgd2F5IG9mIG1ha2luZyBhIHZlY3RvciBpcyB0byBhZGQgdGhlIGFyZ3VtZW50cyB5b3Ugd2FudCwgbnVtYmVycyBpbiB0aGlzIGNhc2UuCgpSdW4gdGhpcyBjb2RlIGNodW5rIHRvIHRlc3QgaXQgb3V0LgoKYGBge3J9CnZlY3QxIDwtIGMoMSw2LDE5LDQsOSkKdmVjdDEKYGBgCgpXZSBjYW4gYWxzbyBjb21iaW5lIHByZWRlZmluZWQgdmFyaWFibGVzIGFuZCB2ZWN0b3JzIHRvZ2V0aGVyIHRvIGNyZWF0ZSBhIG5ldyB2ZWN0b3IuCgpgYGB7cn0KeCA8LSAzMAp2ZWN0MiA8LSBjKHZlY3QxLCAyMiwgNywgeCkKdmVjdDIKYGBgCgpBbm90aGVyIHdheSBvZiBtYWtpbmcgYSB2ZWN0b3IgaXMgdXNpbmcgdGhlIGNvbG9uIChgOmApLCB3aGljaCBjYW4gYmUgZG9uZSB3aXRob3V0IHRoZSBjIGZ1bmN0aW9uLiBXZSBjYW4gdGVsbCBSIHRvIHNlbGVjdCBhIHNlcXVlbmNlIG9mIGludGVnZXJzIGZyb20geCB0byB5LCBvciA1IHRocm91Z2ggdG8gMTAgaW4gb3VyIGV4YW1wbGUuCgpgYGB7cn0KdmVjdDMgPC0gNToxMAp2ZWN0MwpgYGAKCldlIGNhbiBhbHNvIGRvIHNvbWUgYmFzaWMgY2FsY3VsYXRpb25zIG9uIHZlY3RvcnMuIFRoZXNlIG9jY3VyIGVsZW1lbnR3aXNlIChvbmUgZWxlbWVudCBhdCBhIHRpbWUpLgoKYGBge3J9CnZlY3QzLzUKYGBgCgpBcyB5b3UgY2FuIHNlZSB0aGlzIGRpdmlkZXMgYWxsIGVsZW1lbnRzIGluIHRoZSB2ZWN0b3IgYnkgNS4KCiMjIFZlY3RvciBleGVyY2lzZSAxCgoxKSAgTWFrZSBhIHZlY3RvciBjYWxsZWQgeCB3aXRoIGludGVnZXJzIGZyb20gOCB0aHJvdWdoIHRvIDE0CjIpICBBZGQgNSB0byB5b3VyIHggdmVjdG9yIChiZSBzdXJlIHRvIHNhdmUgYXMgcmVzdWx0IGJhY2sgdG8geCkKMykgIE1ha2UgYSB2ZWN0b3IgY2FsbGVkIHkgd2l0aCB2YXJpYWJsZXMgMzQsIDU1LCAxMywgNzEsIDk4LCA0MyBhbmQgMjUKNCkgIFRha2UgMTIgZnJvbSB5b3VyIHkgdmVjdG9yIChiZSBzdXJlIHRvIHNhdmUgYXMgcmVzdWx0IGJhY2sgdG8geSkKNSkgIFRpbWVzIHggdmVjdG9yIGJ5IHkKCmBgYHtyfQojIHlvdXIgY29kZSBoZXJlCgpgYGAKCiMgRnVuY3Rpb25zOiB3aGF0IGFyZSB0aGV5IGFuZCBob3cgdG8gdXNlIHRoZW0KCkEgZnVuY3Rpb24gaXMgY29kZSBvcmdhbmlzZWQgdG9nZXRoZXIgdG8gcGVyZm9ybSBhIHNwZWNpZmljIHRhc2suIFRoZSBmdW5jdGlvbiB3aWxsIHRha2UgaW4gYW4gaW5wdXQsIHBlcmZvcm0gYSB0YXNrLCB0aGVuIHJldHVybiBhbiBvdXRwdXQuIFRoZXkgYXJlIHRoZSBiYWNrYm9uZSBvZiBSLCB3aGljaCBjb21lcyBidWlsdCBpbiB3aXRoIGEgd2lkZSBhcnJheSBvZiBmdW5jdGlvbnMuCgpUaGUgKipmdW5jdGlvbihpbnB1dCkqKiBmb3JtYXQgaXMgdGhlIGZ1bmRhbWVudGFsIHdheSB0byBjYWxsIGFuZCB1c2UgYSBmdW5jdGlvbiBpbiBSLiAqKmZ1bmN0aW9uKiogaXMgdGhlIG5hbWUgb2YgdGhlIGZ1bmN0aW9uIHdlIGFyZSB1c2luZywgKippbnB1dCoqIGlzIHRoZSBhcmd1bWVudCBvciBkYXRhIHdlIGFyZSBwYXNzaW5nIHRvIHRoZSBmdW5jdGlvbi4KCkZvciBleGFtcGxlOgoKYGBge3J9CiMgcnVubmluZyB0aW1lcyAobWlucykKcnVuVGltZXMgPC0gYygzMSwgNTAsIDE1LCAxOSwgMjMsIDM0LCA5KQojIG1lYW4gcnVubmluZyB0aW1lCmF2ZVJ1biA8LSBtZWFuKHJ1blRpbWVzKQphdmVSdW4KIyB0aWR5IHVwIHJlc3VsdAphdmVSdW4gPC0gcm91bmQoYXZlUnVuLCBkaWdpdHMgPSAyKQphdmVSdW4KYGBgCgpIZXJlIHdlIGFyZSB1c2luZyB0aGUgZnVuY3Rpb25zIGBjKClgIHRvIGNvbmNhdGVuYXRlLCBgbWVhbigpYCBjYWxjdWxhdGVzIHRoZSBtZWFuLCBhbmQgYHJvdW5kKClgIHJvdW5kcyB0byBzcGVjaWZpYyBkZWNpbWFsIHBsYWNlcy4gTm90aWNlIHdpdGggdGhlIGByb3VuZCgpYCBmdW5jdGlvbiB3ZSBoYXZlIGBkaWdpdHMgPSAyYCwgd2hpY2ggdGVsbHMgdGhlIGZ1bmN0aW9uIHRvIHJvdW5kIHRvIHR3byBkZWNpbWFsIHBsYWNlczsgdGhpcyBpcyBjYWxsZWQgYSAqYXJndW1lbnQqLgoKIyMgRnVuY3Rpb25zIGV4ZXJjaXNlCgpXZSBhcmUgb24gYSB3YWxraW5nIGV4ZXJjaXNlIHBsYW4sIHdoZXJlIHdlIGluY3JlYXNlIG91ciBzdGVwIGNvdW50IGJ5IGEgdGhvdXNhbmQgZWFjaCBkYXksIHN0YXJ0aW5nIGF0IDEwMDAgc3RlcHMgYW5kIGVuZGluZyBvbiAxMjAwMC4KCjEpICBNYWtlIGEgdmFyaWFibGUgY2FsbGVkIHN0ZXBzIHVzaW5nIHRoZSBgc2VxKClgIGZ1bmN0aW9uIHRoYXQgaW5jcmVhc2VzIHN0ZXBzIGZyb20gMTAwMCB0byAxMjAwMCBieSBpbmNyZW1lbnRzIG9mIDUwMAoyKSAgV29ya291dCB0aGUgc3VtIG9mIGhvdyBtYW55IHN0ZXBzIHdlIGhhdmUgZG9uZSBpbiB0b3RhbCBmcm9tIHRoaXMgZXhlcmNpc2UgcGxhbgozKSAgV29ya291dCBvdXQgdGhlIG1lZGlhbiBhbW91bnQgb2Ygc3RlcHMgd2UgaGF2ZSBkb25lIG9uIHRoaXMgZXhlcmNpc2UgcGxhbgo0KSAgQ29tbWVudCB5b3VyIGNvZGUKCmBgYHtyfQojIHlvdXIgY29kZSBoZXJlCiMgc3RlcHMKCiMgdG90YWwgc3RlcHMKCiMgbWVkaWFuIHN0ZXBzCgpgYGAKCiMgSW5kZXhpbmcgdmVjdG9ycwoKSW5kZXhpbmcgaXMgYSB0ZWNobmljYWwgdGVybSBmb3IgYWNjZXNzaW5nIGVsZW1lbnRzIG9mIGEgdmVjdG9yLiBUaGluayBvZiBpdCBsaWtlIHNlbGVjdGluZyBib29rcyBmcm9tIGEgYm9vayBzaGVsZi4gVGhlIHZlY3RvciBpcyB5b3VyIGJvb2sgc2hlbGYsIHRoZSBpbmRleCBkZXRlcm1pbmVzIHRoZSBib29rLCBvciBib29rcyB5b3UgcGljayBmcm9tIHRoZSBzaGVsZi4KCiFbRGVzaWduZWQgYnkgbWFjcm92ZWN0b3IgLyBGcmVlcGlrXShodHRwczovL2dpdGh1Yi5jb20vYW5kcmV3bW9sZXMyL3JUcmFpbkludHJvZHVjdGlvbi9ibG9iL21haW4vci1mdW5kYW1lbnRhbHMtMi9pbWFnZXMvNjcxNC5qcGc/cmF3PXRydWUpe3dpZHRoPSIzMCUifQoKVG8gaW5kZXggaW4gUiB5b3UgdXNlIHRoZSBzcXVhcmUgYnJhY2tldHMgYFtdYCBhZnRlciB5b3UgdHlwZSB0aGUgbmFtZSBvZiB0aGUgdmVjdG9yIHRvIGluZGV4IGZyb20uIFlvdSB0aGVuIHB1dCB0aGUgbnVtZXJpY2FsIHBvc2l0aW9uIG9mIHRoZSBlbGVtZW50cyB5b3Ugd2FudCB0byBpbmRleCBpbiB0aGUgc3F1YXJlIGJyYWNrZXRzLiBGb3IgZXhhbXBsZSwgaWYgSSB3YW50ZWQgdG8gc2VsZWN0IHRoZSBmaXJzdCBlbGVtZW50IGZyb20gbXkgdmVjdG9yIEkgd291bGQgZG8gc29tZXRoaW5nIGxpa2UgYGRhdGFbMV1gOyBkYXRhIGlzIG15IGRhdGEsIGFuZCAxIGlzIHRoZSBlbGVtZW50IEkgd2FudCB0byBpbmRleC4KClJ1biB0aGUgZXhhbXBsZSBjb2RlIGNodW5rcyB0byBzZWUgdGhlIHJlc3VsdHM6CgpgYGB7cn0Kc29tZU51bWJlcnMgPC0gYyg0LCAyNiwgMTEsIDE1LCAxOCwgOSwgMywgMSkKIyBpbmRleGluZyB0aGUgNnRoIGVsZW1lbnQKc29tZU51bWJlcnNbNl0KYGBgCgpJbmRleGluZyBlbGVtZW50cyAxIHRvIDQKCmBgYHtyfQpzb21lTnVtYmVyc1sxOjRdCmBgYAoKRHJvcHBpbmcgZWxlbWVudHMgNSB0byA3CgpgYGB7cn0Kc29tZU51bWJlcnNbLTU6LTddCmBgYAoKSW5kZXhpbmcgMSwgNSwgYW5kIDgKCmBgYHtyfQpzb21lTnVtYmVyc1tjKDEsNSw4KV0KYGBgCgojIyBJbmRleGluZyBleGVyY2lzZSAxCgpZb3UndmUgYmVlbiBrZWVwaW5nIHRyYWNrIG9mIGhvdyBtdWNoIGNvZmZlZSB5b3UgZHJpbmsgZWFjaCBkYXkgZm9yIGEgdHdvIHdlZWsgcGVyaW9kLiBXZSB3YW50IHRvIHNwbGl0IHRoaXMgaW50byB3ZWVrIDEgYW5kIDIuIFVzaW5nIHRoZSBjb2RlIGJlbG93IGZvbGxvdyB0aGUgZm9sbG93aW5nIHN0ZXBzOgoKMSkgIEZpbmQgb3V0IHRoZSBtZWFuIGZvciB3ZWVrT25lIGFuZCBXZWVrVHdvIHZlY3RvcnMuCjIpICBgbWVhbmAgZG9lc24ndCB3b3JrIGZvciB3ZWVrVHdvIGFuZCBnaXZlcyBiYWNrIGBOQWAuIFByaW50IHlvdXIgd2Vla1R3byB2ZWN0b3IgdG8gbG9vayBhdCB0aGUgZGF0YS4KMykgIENoZWNrIHRoZSBsZW5ndGggb2YgeW91ciB3ZWVrVHdvIHZlY3RvciBieSBydW5uaW5nIHRoZSBgbGVuZ3RoKClgIGZ1bmN0aW9uIG9uIHRoZSB3ZWVrVHdvIHZlY3Rvci4KNCkgIFRoZXJlIGFyZSBhIGZldyB3YXlzIHdheXMgdG8gZml4IHRoaXMsIHRyeSBhbmQgZmluZCBhdCBsZWFzdCB0d28gZGlmZmVyZW50IHdheXMuCgoqaGludDogdGhlIG1lYW4oKSBmdW5jdGlvbiBoYXMgYW4gYXJndW1lbnQgY2FsbGVkIG5hLnJtLCB0eXBlIGFuZCBydW4gP21lYW4oKSB0byBsb29rIGF0IHRoZSBoZWxwIHBhZ2UqCgpgYGB7cn0KIyB2ZWN0b3Igd2l0aCBuIGNvZmZlZSBwZXIgZGF5IGZvciB0d28gd2Vla3MKY29mZmVlIDwtIGMoMywgNSwgNCwgMiwgMywgMSwgMSwgNiwgMiwgMywgMiwgNCwgMiwgMSkKCiMgd2Vla3MKd2Vla09uZSA8LSBjb2ZmZWVbMTo3XQp3ZWVrVHdvIDwtIGNvZmZlZVs4OjE1XQoKIyB5b3VyIGNvZGUgaGVyZQoKYGBgCgojIFVzaW5nIGluZGV4aW5nIHRvIGNoYW5nZSB2YWx1ZXMKClVzaW5nIGluZGV4aW5nIHlvdSBjYW4gY2hhbmdlIHRoZSB2YWx1ZSBvZiBhbiBpdGVtLCBvciBtdWx0aXBsZSBpdGVtcywgaW4gYSB2ZWN0b3IuIFRoaXMgaXMgdmVyeSB1c2VmdWwgaWYgeW91IHNwb3QgYSBkYXRhIGVycm9yIGFuZCB3YW50IHRvIGZpeCBpdCBpbiB0aGUgY29kZS4gV2Ugd2lsbCB1c2luZyBzaW1pbGFyIHByaW5jaXBsZXMgaW4gbGF0ZXIgc2Vzc2lvbnMuCgpUaGlzIGlzIGEgY29tYmluYXRpb24gb2Ygd2hhdCB3ZSBoYXZlIGxlYXJuZWQgc28gZmFyLCB3aXRoIHJlYXNzaWduaW5nIGRhdGEgdG8gdmFyaWFibGVzL3ZlY3RvcnMgYW5kIGluZGV4aW5nLiBGb3IgZXhhbXBsZSwgYGRhdGFbMV0gPC0gNWAgbWVhbnMgd2UgdGFrZSB0aGUgZmlyc3QgZWxlbWVudCAob3IgZGF0YSBwb2ludCkgZnJvbSBkYXRhLCBhbmQgYXNzaWduIHRoZSBudW1iZXIgNSBhcyBhIHJlcGxhY2VtZW50LgoKUnVuIHRoZSBjb2RlIGJlbG93IHRvIHNlZSB0aGUgZXhhbXBsZToKCmBgYHtyfQpzb21lTnVtYmVycyA8LSBjKDQsIDI2LCAxMSwgMTUsIDE4LCA5LCAzLCAxKQpzb21lTnVtYmVycwojIENoYW5nZSBvbmUgaXRlbQpzb21lTnVtYmVyc1s4XSA8LSA1MApzb21lTnVtYmVycwojIENoYW5nZSBtdWx0aXBsZQpzb21lTnVtYmVyc1sxOjNdIDwtIGMoMTksIDIwLCAyMSkKc29tZU51bWJlcnMKYGBgCgpJbiB0aGUgZmlyc3QgY2hhbmdlLCB3ZSBjaGFuZ2VkIHRoZSA4dGggZWxlbWVudCBvZiB0aGUgc29tZU51bWJlcnMgZGF0YSB0byA1MCAoaXQgd2FzIDEgcHJldmlvdXNseSkuIEluIHRoZSBzZWNvbmQgY2hhbmdlLCB3ZSBjaGFuZ2VkIHRoZSBmaXJzdCwgc2Vjb25kIGFuZCB0aGlyZCBlbGVtZW50cyB0byAxOSwgMjAsIGFuZCAyMSAoY2hhbmdpbmcgZnJvbSA0LCAyNiwgMTEpLgoKIyMgSW5kZXhpbmcgZXhlcmNpc2UgMgoKWW91IGRlY2lkZWQgdG8gdHJhY2sgeW91ciB0b3RhbCBtb250aGx5IGV4cGVuZGl0dXJlcyBmb3IgdGhlIHllYXIgdG8gZmluZCBvdXQgbW9yZSBhYm91dCB5b3VyIG1vbnRobHkgc3BlbmRpbmcuIFlvdSdyZSBpbnRlcmVzdGVkIGluIHlvdXIgc3BlbmRpbmcgcGVyIHF1YXJ0ZXIsIGJpZ2dlc3Qgc3BlbmRpbmcgbW9udGgsIGFuZCBsb3dlc3Qgc3BlbmRpbmcgbW9udGguCgoxKSAgTWFrZSBhIHZhcmlhYmxlIGNhbGxlZCBteUV4cGVuc2VzIHdpdGggdGhlIGZvbGxvd2luZyBkYXRhOiA5NzYsIDYzMSwgMTIzMSwgMTEyMCwgMTM3NCwgODczLCAxMjQ0LCAxMzk4LCA5ODksIDEwMzQsIDU3OSBhbmQgMTUwNi4gRWFjaCBpdGVtIHJlcHJlc2VudHMgZWFjaCBtb250aCwgZmlyc3QgaXMgSmFudWFyeSBzcGVuZGluZywgc2Vjb25kIGlzIEZlYnJ1YXJ5IHNwZW5kaW5nIGV0Yy4KMikgIFlvdSByZWFsaXNlIHRoZSBzcGVuZGluZyBmb3Igc29tZSBvZiB0aGUgbW9udGhzIGlzIHdyb25nLiBKYW51YXJ5IHNob3VsZCBiZSA5MjEsIEF1Z3VzdCBzaG91bGQgYmUgMTQxOSwgYW5kIE5vdmVtYmVyIHNob3VsZCBiZSA3MDMuIFVzZSBpbmRleGluZyB0byBjaGFuZ2UgdGhlIHZhbHVlcyBpbiBteUV4cGVuc2VzIHNvIHRoZXkgYXJlIGNvcnJlY3QuXAozKSAgVXNpbmcgaW5kZXhpbmcgbWFrZSBhIHZlY3RvciBmb3IgdGhlIGZpcnN0IHF1YXJ0ZXIgb2YgdGhlIHllYXIuIENhbGwgaXQgUTEgYW5kIG1ha2Ugc3VyZSB0aGUgZmlyc3QgdGhyZWUgbW9udGhzIGFyZSBpbmRleGVkLgo0KSAgUmVwZWF0IGZvciBxdWFydGVycyAyLCAzLCBhbmQgNC4KNSkgIFdvcmtvdXQgdGhlIGF2ZXJhZ2Ugc3BlbmRpbmcgZm9yIGVhY2ggcXVhcnRlci4gV2hpY2ggaGFkIHRoZSBiaWdnZXN0IHNwZW5kaW5nPwo2KSAgVXNpbmcgdGhlIGB3aGljaC5tYXgoKWAgYW5kIGB3aGljaC5taW4oKWAgZnVuY3Rpb25zIG9uIHlvdXIgbXlFeHBlbnNlcyB2ZWN0b3IsIGZpbmQgb3V0IHdoaWNoIG1vbnRocyBoYWQgdGhlIGhpZ2hlc3QgYW5kIGxvd2VzdCBzcGVuZGluZy4gQXNzaWduIHRoZSByZXN1bHQgb2YgZWFjaCB0byBhIHZhcmlhYmxlIChtaW5TcGVuZCwgbWF4U3BlbmQpLgo3KSAgTm93IHlvdSBrbm93IHRoZSBoaWdoZXN0IGFuZCBsb3dlc3Qgc3BlbmRpbmcgbW9udGhzLCBwdXQgdGhlbSBpbnRvIGEgdmVjdG9yIHRvZ2V0aGVyIGNhbGxlZCBNYXhNaW4gYnkgaW5kZXhpbmcgZnJvbSB0aGUgbXlFeHBlbnNlcyB2ZWN0b3IuCgpgYGB7cn0KIyBlbnRlciB5b3VyIGNvZGUgaGVyZQoKYGBgCgojIEZpbmFsIHRhc2sgLSBQbGVhc2UgZ2l2ZSB1cyB5b3VyIGluZGl2aWR1YWwgZmVlZGJhY2shCgpXZSB3b3VsZCBiZSBncmF0ZWZ1bCBpZiB5b3UgY291bGQgdGFrZSBhIG1pbnV0ZSBiZWZvcmUgdGhlIGVuZCBvZiB0aGUgd29ya3Nob3Agc28gd2UgY2FuIGdldCB5b3VyIGZlZWRiYWNrIQoKPGh0dHBzOi8vbHNlLmV1LnF1YWx0cmljcy5jb20vamZlL2Zvcm0vU1ZfZWZsYzJ5ajRwY3J5YzYyP2NvdXJzZW5hbWU9UiUyMEZ1bmRhbWVudGFscyUyMDElMjAmJTIwMjolMjBGYXN0LXRyYWNrJTIwUGlsb3QmdG9waWM9UiZsaW5rPWh0dHBzOi8vbHNlY2xvdWQuc2hhcmVwb2ludC5jb20vOnU6L3MvVEVBTV9BUEQtRFNMLURpZ2l0YWwtU2tpbGxzLVRyYWluZXJzL0VWNjRFb1B0cElaQm5KWFVIU0ROd3hnQkMtRnVXU1lvZVhVdkFha1hNWk1Pa0EmcHJvZz1EUyZ2ZXJzaW9uPTIxLTIyJmxpbmsyPWh0dHBzOi8vbHNlY2xvdWQuc2hhcmVwb2ludC5jb20vOnU6L3MvVEVBTV9BUEQtRFNMLURpZ2l0YWwtU2tpbGxzLVRyYWluZXJzL0VXWmNkaEEtUE5KTm9PQjNrSUhQZ1QwQnljWVg5X05IaTBiZDhkaEg5eGptV3c+CgpUaGUgc29sdXRpb25zIHdpbGwgYmUgYXZhaWxhYmxlIGZyb20gYSBsaW5rIGF0IHRoZSBlbmQgb2YgdGhlIHN1cnZleS4KCiMgSW5kaXZpZHVhbCBjb2RpbmcgY2hhbGxlbmdlIDEKCllvdSBkZWNpZGUgdG8gY2FsY3VsYXRlIHlvdXIgY29tbXV0aW5nIHRpbWVzIG92ZXIgYSB3ZWVrbHkgcGVyaW9kLiBZb3UgZGVjaWRlIHRvIHNlZSBpZiB5b3UgY2FuIHdvcmtvdXQsIGJhc2VkIG9mZiB5b3VyIHdlZWtseSBjb21tdXRlLCBob3cgbXVjaCBjb21tdXRpbmcgeW91IHdpbGwgZG8gb24gYXZlcmFnZSB0aGlzIG1vbnRoLgoKMSkgIFJlcGxpY2F0ZSB0aGUgY29tbXV0ZSB2YXJpYWJsZSBmb3VyIHRpbWVzIHVzaW5nIGByZXAoKWAgYW5kIGFzc2lnbiB0byBhIHZhcmlhYmxlIGNhbGxlZCBjb21tdXRlX2VzdC4KMikgIENhbGN1bGF0ZSB0aGUgbWVhbiBvZiBjb21tdXRlX2VzdCBhbmQgYXNzaWduIHRvIGEgdmFyaWFibGUgY2FsbGVkIGF2ZUNvbW11dGUuCjMpICBSb3VuZCB0aGUgdmFsdWUgb2YgYXZlQ29tbXV0ZSB0byB0d28gZGVjaW1hbCBwbGFjZXMgdXNpbmcgYHJvdW5kKClgIGFuZCBhc3NpZ24gdG8gYXZlQ29tbXV0ZS4KNCkgIFlvdSBtaXNzIHRpbWVkIHlvdXIgVHVlc2RheSBjb21tdXRlLCBpdCBzaG91bGQgYmUgMzcgaW5zdGVhZCBvZiAzMy4gVG8gbWFrZSByZXBsYWNlbWVudCBlYXNpZXIgdXNlIGBzb3J0KClgIG9uIGNvbW11dGVfZXN0LCBhbmQgYXNzaWduIHRvIGEgdmFyaWFibGUgY2FsbGVkIGNvbW11dGVfc29ydC4KNSkgIFJlcGxhY2UgdGhlIDMzIHZhbHVlcyB3aXRoIDM3IHVzaW5nIGluZGV4aW5nIGluIHRoZSB2YXJpYWJsZSBjb21tdXRlX3NvcnQuCjYpICBSZS1jYWxjdWxhdGUgYW5kIHJvdW5kIGF2ZUNvbW11dGUgYXMgcGVyIGluc3RydWN0aW9ucyB0d28gYW5kIHRocmVlLgo3KSAgVGVzdCBvdXQgdGhlIGZvbGxvd2luZyBmdW5jdGlvbnMgb24gdGhlIGNvbW11dGVfc29ydCB2YXJpYWJsZTogYHVuaXF1ZSgpYCBhbmQgYHNvcnQoY29tbXV0ZSwgZGVjcmVhc2luZyA9IFRSVUUpYC4KCmBgYHtyfQpjb21tdXRlIDwtIGMoNDEsIDMzLCA0NCwgNTIsIDM2LCAzOSkKIyBlbnRlciB5b3VyIGNvZGUgaGVyZQoKYGBgCgojIEluZGl2aWR1YWwgY29kaW5nIGNoYWxsZW5nZSAyCgpGb3IgdGhpcyBpbmRpdmlkdWFsIGNvZGluZyBjaGFsbGVuZ2Ugd2Ugd2lsbCBiZSBsb29raW5nIGF0IExpb25hbCBNZXNzaSdzIHNlYXNvbiBhcHBlYXJhbmNlcyBhbmQgZ29hbHMgZnJvbSAyMDA0LTIwMjAuIAoKVGhlIGNvZGUgYmVsb3cgaGFzIGJlZW4ganVtYmxlZCB1cCBhbmQgd2lsbCBub3QgcnVuLiBZb3VyIGNoYWxsZW5nZSBpcyB0byByZS1vcmRlciBpdCBzbyBpdCBydW5zIGNvcnJlY3RseS4gSXQgc2hvdWxkIHByaW50IG91dCBzdW1tYXJ5IHN0YXRpc3RpY3MgZm9yIHNlYXNvbiBnb2FsIHJhdGlvIGFuZCBhZ2UgYmFuZCBnb2FsIHJhdGlvcywgYXMgd2VsbCBhcyB3aGljaCB5ZWFyIHdhcyBoaXMgbW9zdCBhbmQgbGVhc3QgcHJvbGlmaWMsIGFuZCBob3cgbWFueSB5ZWFycyB0aGF0IHRvb2sgaGltLiAKCmBgYHtyIGVycm9yPVRSVUV9CiMgcHJpbnQgY2FyZWVyIHJhdGlvCmNhcmVlckdvYWxSYXRpbwoKIyB3aGljaCBzZWFzb24gaGFkIHRoZSB3b3JzdCBnb2FsIHJhdGlvCnNlYXNvblt3aGljaC5tYXgoZ29hbFJhdGlvKV0KCiMgY29tYmluZSBhZ2UgYmFuZCByYXRpb3MgdG8gYSB2ZWN0b3IKYWdlR29hbFJhdGlvIDwtIGMocm91bmQobWVhbih0ZWVuYWdlR29hbFJhdGlvKSwgZGlnaXRzID0gMiksIAogICAgICAgICAgICAgIHJvdW5kKG1lYW4odHdlbnRpZXNHb2FsUmF0aW8pLCBkaWdpdHMgPSAyKSwKICAgICAgICAgICAgICByb3VuZChtZWFuKHRoaXJ0aWVzR29hbFJhdGlvKSwgZGlnaXRzID0gMikpCgojIGFkZCBpbiBhcHBlYXJhbmNlLCBnb2FsIGFuZCBzZWFzb24gZGF0YQphcHBlYXJhbmNlcyA8LSBjKDksMjUsMzYsNDAsNTEsNTMsNTUsNjAsNTAsNDYsNTcsNDksNTIsNTQsNTAsNDQpCmdvYWxzIDwtIGMoMSw4LDE3LDE2LDM4LDQ3LDUzLDczLDYwLDQxLDU4LDQxLDU0LDQ1LDUxLDMxKQpzZWFzb24gPC0gYygyMDA0LDIwMDUsMjAwNiwyMDA3LDIwMDgsMjAwOSwyMDEwLDIwMTEsMjAxMiwKICAgICAgICAgICAgMjAxMywyMDE0LDIwMTUsMjAxNiwyMDE3LDIwMTgsMjAxOSkKCiMgd2hpY2ggc2Vhc29uIGhhZCB0aGUgYmVzdCBnb2FsIHJhdGlvCnNlYXNvblt3aGljaC5taW4oZ29hbFJhdGlvKV0KCiMgZ29hbCByYXRpbyBwZXIgYWdlIGJhbmQgKHRlZW5hZ2VyLCAyMCdzLCAzMCdzKQp0ZWVuYWdlR29hbFJhdGlvIDwtIGdvYWxSYXRpb1sxOjNdCnR3ZW50aWVzR29hbFJhdGlvIDwtIGdvYWxSYXRpb1s0OjEzXQp0aGlydGllc0dvYWxSYXRpbyA8LSBnb2FsUmF0aW9bMTQ6MTZdCgojIHN1bW1hcnkgcmVzdWx0cwpzdW1tYXJ5KGdvYWxSYXRpbykKc3VtbWFyeShhZ2VHb2FsUmF0aW8pCgojIGhvdyBtYW55IHllYXJzIHBsYXlpbmcgdG8gcmVhY2ggYmVzdCBnb2FsIHJhdGlvCnNlYXNvblt3aGljaC5taW4oZ29hbFJhdGlvKV0gLSBzZWFzb25bMV0KCiMgd29yayBvdXQgYXBwZWFyYW5jZSB0byBnb2FsIHJhdGlvIHBlciBzZWFzb24gYW5kIHRvdGFsIGNhcmVlciByYXRpbwpnb2FsUmF0aW8gPC0gcm91bmQoYXBwZWFyYW5jZXMvZ29hbHMsIGRpZ2l0cyA9IDIpCmNhcmVlckdvYWxSYXRpbyA8LSByb3VuZChzdW0oYXBwZWFyYW5jZXMpL3N1bShnb2FscyksIGRpZ2l0cyA9IDIpCmBgYAoKCg==